using System;
using System.Text;
using System.Net.Sockets;
using System.IO;

// Copyright 2009 (c) SocketDemo.

namespace SocketDemo
{
    /// <summary>
    /// Client Helper.
    /// </summary>
    public class ClientHelper
    {
        #region field

        public delegate void ReceiveData(TcpClient client, string data);

        public static ReceiveData delReceiveData = null;

        private const int READ_BUFFER_SIZE = 5120;
        private static byte[] readBuffer = new byte[READ_BUFFER_SIZE];

        #endregion

        #region Connect Socket
        public static bool ConnectSocket(
           ref TcpClient client,
           string remoteHost,
           int remotePort,
            AsyncCallback asyncCallback)
        {

            try
            {
                #region main process

                if (client == null || client.Client == null)
                {
                    client = new TcpClient();
                }

                if (client.Connected)
                {
                    LogHelper.ShowLog("Re-Connect\t" + DateTime.Now.ToString() + "\t" +
                        "close current connect\t" + client.GetHashCode().ToString());

                    if (client.GetStream() != null)
                    {
                        client.GetStream().Close();
                    }

                    client.Close();
                    client = new TcpClient();

                    LogHelper.ShowLog("Create Client\t" + DateTime.Now.ToString() + "\t" +
                        client.GetHashCode().ToString());
                }

                try
                {
                    client.Connect(remoteHost, remotePort);
                }
                catch (ObjectDisposedException)
                {
                    client = new TcpClient();
                    client.Connect(remoteHost, remotePort);

                    LogHelper.ShowLog("Create Client\t" + DateTime.Now.ToString() + "\t" +
                        client.GetHashCode().ToString());
                }

                client.GetStream().BeginRead(readBuffer, 0,
                    READ_BUFFER_SIZE, asyncCallback, client);

                #endregion

                return true;
            }
            catch (SocketException ex)
            {
                if (client != null)
                {
                    client.Close();
                }

                ExceptionHelper.ShowException(ex);
            }
            catch (Exception ex)
            {
                if (client != null)
                {
                    client.Close();
                }

                ExceptionHelper.ShowException(ex);
            }

            return false;
        } 
        #endregion

        #region Close
        public static void Close(TcpClient client)
        {
            try
            {
                if (client == null)
                {
                    return;
                }

                if (client.GetStream() != null)
                {
                    client.GetStream().Close();
                }

                client.Close();
                System.Threading.Thread.Sleep(100);

            }
            catch (Exception ex)
            {
                ExceptionHelper.ShowException(ex);
            }
        } 
        #endregion

        #region DoReading
        public void DoReading(IAsyncResult ar)
        {
            int BytesRead = 0;
            string strReceiveData = string.Empty;
            TcpClient client = null;

            try
            {
                client = (TcpClient)ar.AsyncState;

                if (client.Connected)
                {
                    lock (client.GetStream())
                    {
                        BytesRead = client.GetStream().EndRead(ar);
                    }
                }

                if (BytesRead > 0)
                {
                    strReceiveData = Encoding.UTF8.GetString(readBuffer, 0, BytesRead);

                    (new ReceiveData(HandleReceive)).BeginInvoke(client, strReceiveData,
                        new AsyncCallback(ReceiveCallback), client);
                }
                else
                {
                    client.Close();

                    LogHelper.ShowLog("Connect Closed\t" + DateTime.Now.ToString() + "\t" +
                        client.GetHashCode().ToString());

                    return;
                }
            }
            catch (IOException ex)
            {
                client.Close();
                ExceptionHelper.ShowException(ex);
            }
            catch (Exception ex)
            {
                client.Close();
                ExceptionHelper.ShowException(ex);
            }
        } 
        #endregion

        #region HandleReceive
        public static void HandleReceive(TcpClient client, string data)
        {
            LogHelper.ShowLog("Receive\t\t" + DateTime.Now.ToString() + "\t" +
                client.GetHashCode().ToString() + "\t" + data);
        } 
        #endregion

        #region ReceiveCallback
        private void ReceiveCallback(IAsyncResult ar)
        {
            TcpClient client = null;
            try
            {
                client = (TcpClient)ar.AsyncState;

                lock (client.GetStream())
                {
                    client.GetStream().BeginRead(readBuffer, 0,
                        READ_BUFFER_SIZE, new AsyncCallback(DoReading), client);
                }
            }
            catch (IOException ex)
            {
                client.Close();
                ExceptionHelper.ShowException(ex);
            }
            catch (ObjectDisposedException ex)
            {
                client.Close();
                ExceptionHelper.ShowException(ex);
            }
            catch (Exception ex)
            {
                client.Close();
                ExceptionHelper.ShowException(ex);
            }
        } 
        #endregion

        #region SendData

        public static bool SendData(
            TcpClient client,
            string sendMessage)
        {
            Byte[] data = null;
            NetworkStream networkStream = null;

            try
            {

                data = System.Text.Encoding.UTF8.GetBytes(sendMessage);

                lock (client.GetStream())
                {
                    networkStream = client.GetStream();
                    networkStream.Write(data, 0, data.Length);
                }

                return true;
            }
            catch (Exception ex)
            {
                ExceptionHelper.ShowException(ex);
            }

            return false;
        }

        #endregion
    }
}
